#include "VideoInMgr.h"
#include "mediaPriv.h"
#include "VideoIn.h"
#include "VideoInMgr.h"
#include "VideoOut.h"
#include "VideoEnc.h"
#include "Thread/Thread.h"
#include "Util/logc.h"
#include "ConfigApi.h"
#include "FormatVideo.h"
#include "VideoEncode.h"

using namespace ConfigApi;

namespace Media{

VideoInMgr *VideoInMgr::s_videoIn = nullptr;

extern "C" void VideoInit(){


	for(int i = 0; i < 3; i++){
		VideoEncode::instance(i);
	}

	VideoInMgr::instance();
}


VideoInMgr* VideoInMgr::instance(){
	if(s_videoIn == nullptr){
		s_videoIn = new VideoInMgr;
	}
	return s_videoIn;
}

VideoInMgr::VideoInMgr(){
	if(!createVideoIn()){
		errorf("VideoInMgr createVideoIn error");
	}

	//initConfig();
}

bool VideoInMgr::createVideoIn(){
    int status;
    int viNums;
    VideoInDesc inputDesc;
    VideoInOptions inOptions;
    VideoColor videoColor;
    VideoInFormat viFormat;
    VideoStandard standard;
    MEDIA_cfg_t *pCfg;

    pCfg = &mediaCtl_g.cfg;

    standard = videoStandardNTSC;

    viNums = getVideoInputChannels();
    if (viNums <= 0)
    {
        tracef("vi nums(%d) is invalid.", viNums);
        return false;
    }

    inputDesc.card = 0;
    inputDesc.channel = 0;
    inputDesc.standard = standard;
    status = createVideoInput(&inputDesc, &mediaCtl_g.pVideoInput);

    if (status)
    {
        tracef("create video input failed!");
        return false;
    }

    _videoInput = mediaCtl_g.pVideoInput;

#if 0
    status = _videoInput->setStandard(_videoInput, standard);
    if (status)
    {
        tracef("set standard failed!");
        return false;
    }
    status = _videoInput->getFormatCaps(_videoInput, standard, &viFormat);
    if (status)
    {
        tracef("get format caps failed!\n");
        return false;
    }

    mediaCtl_g.viWidth = viFormat.width;
    mediaCtl_g.viHeight = viFormat.height;
    mediaCtl_g.fps = viFormat.fps;

    Json::Value config0;
	if(!IConfigInterface::GetInstance()->Get("VideoIn.Id0", config0)){
		errorf("VideoInMgr.Id0 get error");
	}
    parseConfig(config0["Options"], _inOptions);

//    status = _videoInput->setOptions(_videoInput, &pCfg->inOptions);
    status = _videoInput->setOptions(_videoInput, &_inOptions);
    if (status)
    {
        tracef("set standard failed!\n");
        return false;
    }
    parseConfig(config0["Color"], _videoColor);
    status = _videoInput->setColor(_videoInput, &_videoColor);
    if (status)
    {
    	tracef("set color failed!");
        return false;
    }
#endif
    return true;
}

void VideoInMgr::initConfig(){

    IConfigInterface::GetInstance()->Attach("VideoIn.Id0.Color", this, [this](const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
    	return onConfigColor(name, newTable, oldTable, result);
    });
    IConfigInterface::GetInstance()->Attach("VideoIn.Id1.Color", this, [this](const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
    	return onConfigColor(name, newTable, oldTable, result);
    });
    IConfigInterface::GetInstance()->Attach("VideoIn.Id0.Options", this, [this](const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
    	return onConfigOptions(name, newTable, oldTable, result);
    });
    IConfigInterface::GetInstance()->Attach("VideoIn.Id1.Options", this, [this](const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
    	return onConfigOptions(name, newTable, oldTable, result);
    });

    IConfigInterface::GetInstance()->AttachVerify("VideoIn", this, [this](const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
    	return onConfigVerify(name, newTable, oldTable, result);
    });
}

bool VideoInMgr::onConfigColor(const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
	if(name == "VideoIn.Id0.Color"){
		if(parseConfig(newTable, _videoColor)){
			tracef("_videoColor brightness:%d, contrast:%d, saturation:%d, hue:%d", _videoColor.brightness, _videoColor.contrast, _videoColor.saturation, _videoColor.hue);
			if(_videoInput->setColor(_videoInput, &_videoColor) < 0){
				errorf("onConfigColor VideoInMgr.Id0.Color setColor error");
			}
			else{
				tracef("onConfigColor success");
			}
		}
		else{
			errorf("parseConfig _videoColor error");
		}
	}
	else if(name == "VideoIn.Id1.Color"){
		if(parseConfig(newTable, _secVideoColor)){
			if(_videoInputSec->setColor(_videoInputSec, &_secVideoColor) < 0){
				errorf("onConfigColor VideoInMgr.Id1.Color setColor error");
			}
		}
	}

	tracef("onConfigColor Success");
	return true;
}

bool VideoInMgr::onConfigOptions(const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
	if(name == "VideoIn.Id0.Options"){
		if(parseConfig(newTable, _inOptions)){
			if(_videoInput->setOptions(_videoInput, &_inOptions) < 0){
				errorf("onConfigColor VideoIn.Id0.Options setColor error");
			}
		}
	}

	return true;
}

bool VideoInMgr::onConfigVerify(const std::string &name, const Json::Value &newTable, const Json::Value &oldTable, int &result){
	//tracef("onConfig newTable: %s", newTable.toStyledString().c_str());
	//tracef("onConfig newTable: %s", oldTable.toStyledString().c_str());
	return true;
}

bool VideoInMgr::parseConfig(const Json::Value &table, VideoColor &videoColor){
	tracef("parseConfig Color : %s", table.toStyledString().c_str());
	if(!Json::getJsonChar(table, "Brightness", videoColor.brightness)){
		errorf("Brightness error");
		return false;
	}
	if(!Json::getJsonChar(table, "Contrast", videoColor.contrast)){
		errorf("Contrast error");
		return false;
	}
	if(!Json::getJsonChar(table, "Saturation", videoColor.saturation)){
		errorf("Saturation error");
		return false;
	}
	if(!Json::getJsonChar(table, "Hue", videoColor.hue)){
		errorf("Hue error");
		return false;
	}
	return true;
}

bool VideoInMgr::parseConfig(const Json::Value &table, VideoInOptions &inOption){
	bool mirror = false;
	//tracef("parseConfig Option : %s", table.toStyledString().c_str());
	if(!Json::getJsonBool(table, "View.Mirror", mirror)){
		errorf("View.Mirror error");
		return false;
	}
	else{
		inOption.mirror = mirror?1:0;
	}

	bool flip = false;
	if(!Json::getJsonBool(table, "View.Flip", flip)){
		errorf("View.Flip error");
		return false;
	}
	else{
		inOption.flip = flip?1:0;
	}

	int rotate90;
	if(!Json::getJsonInt(table, "View.Rotate90", rotate90)){
		errorf("View.Rotate90 error");
		return false;
	}
	else{
		inOption.rotate90 = rotate90;
	}

	int white = 0;
	if(!Json::getJsonInt(table, "WhiteBalance.Mode", white)){
		errorf("WhiteBalance.Mode error");
		return false;
	}
	inOption.whiteBalance = (WhiteBalancePreset)white;

	if(!Json::getJsonUint16(table, "WhiteBalance.ColorTemp", inOption.colorTemp)){
		errorf("WhiteBalance.ColorTemp error");
		return false;
	}

	if(!Json::getJsonInt(table, "Exposure.Mode", inOption.exposure)){
		errorf("Exposure.Mode error");
		return false;
	}
	if(!Json::getJsonUint8(table, "Exposure.Compansation", inOption.compansation)){
		errorf("Exposure.compansation error");
		return false;
	}

	uint8_t antiFlicker = 0;

	if(!Json::getJsonUint8(table, "AntiFlicker", antiFlicker)){
		errorf("AntiFlicker error");
		return false;
	}
	inOption.antiFlicker = antiFlicker;

	return true;
}

bool VideoInMgr::Start(){
	initConfig();
	return true;
}

extern "C" void VideoInInit(){

	VideoInMgr::instance()->Start();
}

} //namespace Media

